package com.kevin.datasource;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import javax.sql.DataSource;

public class DefaultDataSource implements DataSource{

	private static Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();

	private Properties driverProperties;
	private String driver;
	private String url;
	private String username;
	private String password;
	
	private Boolean autoCommit;
	  private Integer defaultTransactionIsolationLevel;
	  
	public DefaultDataSource(){
		
	}
	public DefaultDataSource(String driver, String url, String username, String password) {
		this.driver = driver;
		this.url = url;
		this.username = username;
		this.password = password;
	}
	  
	static {
	    Enumeration<Driver> drivers = DriverManager.getDrivers();
	    while (drivers.hasMoreElements()) {
	      Driver driver = drivers.nextElement();
	      registeredDrivers.put(driver.getClass().getName(), driver);
	    }	  
	}
	

	public Properties getDriverProperties() {
		return driverProperties;
	}

	public void setDriverProperties(Properties driverProperties) {
		this.driverProperties = driverProperties;
	}

	public String getDriver() {
		return driver;
	}

	public void setDriver(String driver) {
		this.driver = driver;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Boolean getAutoCommit() {
		return autoCommit;
	}

	public void setAutoCommit(Boolean autoCommit) {
		this.autoCommit = autoCommit;
	}

	public Integer getDefaultTransactionIsolationLevel() {
		return defaultTransactionIsolationLevel;
	}

	public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) {
		this.defaultTransactionIsolationLevel = defaultTransactionIsolationLevel;
	}

	@Override
	public Connection getConnection() throws SQLException {
		return doGetConnection(username, password);
	}

	@Override
	public Connection getConnection(String username, String password) throws SQLException {
		return doGetConnection(username, password);
	}
	
	@Override
	public PrintWriter getLogWriter() throws SQLException {
		return null;
	}

	@Override
	public int getLoginTimeout() throws SQLException {
		return DriverManager.getLoginTimeout();
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setLogWriter(PrintWriter logWriter) throws SQLException {
		DriverManager.setLogWriter(logWriter);
	}

	@Override
	public void setLoginTimeout(int loginTimeout) throws SQLException {
		DriverManager.setLoginTimeout(loginTimeout);
	}

	@Override
	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public <T> T unwrap(Class<T> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	private Connection doGetConnection(String username, String password) throws SQLException {
	    Properties props = new Properties();
	    if (driverProperties != null) {
	      props.putAll(driverProperties);
	    }
	    if (username != null) {
	      props.setProperty("user", username);
	    }
	    if (password != null) {
	      props.setProperty("password", password);
	    }
	    return doGetConnection(props);
	}
	private Connection doGetConnection(Properties properties) throws SQLException {
	    initializeDriver();
	    Connection connection = DriverManager.getConnection(url, properties);
	    configureConnection(connection);
	    return connection;
	}  
	private synchronized void initializeDriver() throws SQLException {
		if (!registeredDrivers.containsKey(driver)) {
		    Class<?> driverType;
		    try {
		    	driverType = Class.forName(driver);      
		    	Driver driverInstance = (Driver)driverType.newInstance();    
		    	DriverManager.registerDriver(driverInstance);
		    	registeredDrivers.put(driver, driverInstance);
		    } catch (Exception e) {
		      throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
		    }
		 }
	}
	  
	private void configureConnection(Connection conn) throws SQLException {
	    if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
	      conn.setAutoCommit(autoCommit);
	    }
	    if (defaultTransactionIsolationLevel != null) {
	      conn.setTransactionIsolation(defaultTransactionIsolationLevel);
	    }
		  
	}
}
